Skip to content

fix(wc-memberships): skip expiry filter for non-subscription memberships#4743

Merged
adekbadek merged 1 commit into
trunkfrom
hotfix/membership-expiry-non-subscription-guard
Jun 10, 2026
Merged

fix(wc-memberships): skip expiry filter for non-subscription memberships#4743
adekbadek merged 1 commit into
trunkfrom
hotfix/membership-expiry-non-subscription-guard

Conversation

@adekbadek

Copy link
Copy Markdown
Member

All Submissions:

Changes proposed in this Pull Request:

Membership_Expiry::prevent_membership_expiration() is hooked into wc_memberships_expire_user_membership, which fires for every user membership. The handler assumed every membership was a subscription-tied one (\WC_Memberships_Integration_Subscriptions_User_Membership) and called get_subscription_id() on it. For plain WC_Memberships_User_Membership objects (no linked subscription), that method does not exist, so the call throws Uncaught Error: Call to undefined method WC_Memberships_User_Membership::get_subscription_id().

This adds an early method_exists() guard that returns the incoming $cancel_membership value unchanged when the membership is not subscription-tied, so the filter is effectively a no-op for memberships it cannot reason about. The docblock type for $user_membership is also widened from the integration class to the base class to match reality.

How to test the changes in this Pull Request:

  1. With WC Memberships active but without WC Subscriptions (or with a manually-granted membership that has no linked subscription), expire that membership in the admin or via wp wc memberships .... Confirm no PHP fatal is logged.
  2. With WC Subscriptions active and a subscription-tied membership, cancel the underlying subscription. Confirm the existing behavior still works: if another active subscription for the same product exists, the membership is reassigned and not expired; otherwise it expires normally.
  3. Run the included unit test: composer test -- --filter test_passes_through_non_subscription_membership. It must pass; without the fix it errors with Call to undefined method ... ::get_subscription_id().
  4. Run the full plugin test suite to confirm no regressions: composer test.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully ran tests with your changes locally?

The wc_memberships_expire_user_membership filter fires for every user
membership, not just subscription-tied ones. The handler assumed a
\WC_Memberships_Integration_Subscriptions_User_Membership and called
get_subscription_id() on it; plain WC_Memberships_User_Membership
objects don't have that method, so the call threw an Uncaught Error.

Bail out early via method_exists() and widen the docblock type to the
base class.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a fatal error in Membership_Expiry::prevent_membership_expiration() when the wc_memberships_expire_user_membership filter fires for non-subscription-tied memberships, which don't expose get_subscription_id().

Changes:

  • Adds a method_exists() guard to early-return when the membership object lacks get_subscription_id().
  • Widens the docblock type of $user_membership from the Subscriptions integration class to the base class.
  • Adds a unit test that reproduces the original fatal and verifies pass-through behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
includes/plugins/wc-memberships/class-membership-expiry.php Guards against non-subscription memberships and updates docblock.
tests/unit-tests/plugins/wc-memberships/membership-expiry.php New unit test verifying the filter passes through for non-subscription memberships.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 6.40.0-hotfix-membership-expiry-non-subscription-guard.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@adekbadek adekbadek marked this pull request as ready for review May 19, 2026 08:46
@adekbadek adekbadek requested a review from a team as a code owner May 19, 2026 08:46
@adekbadek adekbadek added the [Status] Needs Review The issue or pull request needs to be reviewed label May 19, 2026

@jason10lee jason10lee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved! Targeted fix, tests clean, even adds to the test suite. (Thank you!)

@github-actions github-actions Bot added [Status] Approved The pull request has been reviewed and is ready to merge and removed [Status] Needs Review The issue or pull request needs to be reviewed labels Jun 9, 2026
@adekbadek adekbadek merged commit 8769161 into trunk Jun 10, 2026
18 checks passed
@adekbadek adekbadek deleted the hotfix/membership-expiry-non-subscription-guard branch June 10, 2026 08:01
@github-actions

Copy link
Copy Markdown

Hey @adekbadek, good job getting this PR merged! 🎉

Now, the needs-changelog label has been added to it.

Please check if this PR needs to be included in the "Upcoming Changes" and "Release Notes" doc. If it doesn't, simply remove the label.

If it does, please add an entry to our shared document, with screenshots and testing instructions if applicable, then remove the label.

Thank you! ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-changelog [Status] Approved The pull request has been reviewed and is ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants